// Globals.cpp : implementation file
// I created this file for shared global type functions to save creating them
// in each class that requires them.
// Author Nic Wilson
// Last Change			:3-10-2001
// Change History
// 3rd October 2001
//						File & code created.
//
#include "StdAfx.h"
#include "Globals.h"
#include "Vfw.h"
#include "logging.h"
#include <fstream>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <windows.h>
#include "vfw.h" 

#ifdef _DEBUG
//#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

ofstream* out;
CLogging* logger;
char str[256];
//LONGLONG llTotalBytes;
//POINT pt, datapt;
//----------------------------------------------------------------------------------------------
// bool GetFiles(HWND owner, OPENFILENAME *ofn, LPSTR Title, LPSTR Title2000, LPCTSTR Filter, LPCTSTR defaultdir, char *PathName, int PathNameSize, char *FileName, int FileNameSize, int Flags, char *defaultext)
// Fetch on or more files depending on parameters supplied.
// PARAMETERS:		HWND owner			=	HWND parameter owner of this window
//					OPENFILENAME *ofn	=	OPENFILENAME struct
//					LPSTR Title			=	Title for requester for Windows older than Windows2000
//					LPSTR Title2000		=	Title for Windows2000 and Windows XP (if NULL Title is used)
//					LPCTSTR Filter		=	Ptr to a buffer of pairs of null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters
//					LPCTSTR defaultdir	=	Directory to open the requester in
//					char *PathName		=	Ptr to a buffer to hold the returned file strings
//					int PathNameSize	=	Size of the above buffer
//					char *FileName		=	Ptr to a buffer to hold filename without path (can be NULL)
//					int FileNameSize	=	Size of above buffer (ignored if above is NULL)
//					int Flags			=	A set of bit flags used to initialise the dialog
//					char *defaultext	=	Ptr to buffer containing the required default extension
//
// RETURN		bool  true = success, false = error
//----------------------------------------------------------------------------------------------
bool GetFiles(HWND owner, OPENFILENAME *ofn, LPSTR Title, LPSTR Title2000, LPCTSTR Filter, LPCTSTR defaultdir, char *PathName, int PathNameSize, char *FileName, int FileNameSize, int Flags, char *defaultext, int defindex)
{
	ZeroMemory(ofn, sizeof(OPENFILENAME));					//set buffer to zero
	char currdir[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, currdir);  //get curr dir
	CString l_InitialDir;							//get a string for the path
	CWinApp *pApp = AfxGetApp();
	if (defaultdir == NULL)
		l_InitialDir = currdir;
	else
	{
		l_InitialDir = GetString(defaultdir, 0);
		SetCurrentDirectory(l_InitialDir);
	}
	if (GetOSVersion() >= WINDOWS2000)		//WINDOWS2000 is defined in this file
	{
		if (Title2000 == NULL)
			ofn->lpstrTitle = Title;
		else
			ofn->lpstrTitle = Title2000;
		ofn->lStructSize = sizeof(OPENFILENAME);
	}
	else
	{
		ofn->lpstrTitle = Title;
		ofn->lStructSize = OPENFILENAME_SIZE_VERSION_400;
	}
	ofn->hwndOwner=owner;
	ofn->lpstrFilter = Filter;	
	ofn->lpstrCustomFilter = NULL;
	ofn->lpstrFile = PathName;
	ofn->nMaxFile = PathNameSize;
	ofn->lpstrFileTitle = FileName;
	ofn->nMaxFileTitle = FileNameSize;
	ofn->lpstrInitialDir = l_InitialDir;
	ofn->Flags = Flags;
	ofn->lpstrDefExt = defaultext;
	if (PathNameSize)
		ZeroMemory(PathName, PathNameSize); 
	if (FileNameSize)
		ZeroMemory(FileName, FileNameSize);  
	GetOpenFileName(ofn);
	GetCurrentDirectory(MAX_PATH, l_InitialDir.GetBuffer(MAX_PATH));  //get curr dir
	l_InitialDir.ReleaseBuffer();
	SetCurrentDirectory(currdir);
	if (PathName[0] == '\0')						//did user choose a file?
		return false;										//nope!
	if (ofn->nFileOffset < 0)
		return false;
//	WriteString(defaultdir, (LPCTSTR)l_InitialDir);
	WriteString(defaultdir, (LPCTSTR)PathName);
//	WriteString((LPCTSTR)"Last FileName", (LPCTSTR)FileName);
	return true;
}

//----------------------------------------------------------------------------------------------
// bool SaveFiles(HWND owner, OPENFILENAME *ofn, LPSTR Title, LPSTR Title2000, LPCTSTR Filter, LPCTSTR defaultdir, char *PathName, int PathNameSize, char *FileName, int FileNameSize, int Flags, char *defaultext)
// Save a file based on parameters supplied.
// PARAMETERS:		HWND owner			=	HWND parameter owner of this window
//					OPENFILENAME *ofn	=	OPENFILENAME struct
//					LPSTR Title			=	Title for requester for Windows older than Windows2000
//					LPSTR Title2000		=	Title for Windows2000 and Windows XP (if NULL Title is used)
//					LPCTSTR Filter		=	Ptr to a buffer of pairs of null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters
//					LPCTSTR defaultdir	=	Directory to open the requester in
//					char *PathName		=	Ptr to a buffer to hold the filename input by the user including path.
//					int PathNameSize	=	Size of the above buffer
//					char *FileName		=	Ptr to a buffer to hold filename input by the user without path (This can be NULL)
//					int FileNameSize	=	Size of above buffer (ignored if above is NULL)
//					int Flags			=	A set of bit flags used to initialise the dialog
//					char *defaultext	=	Ptr to buffer containing the required default extension
//
// RETURN		bool  true = success, false = error
//----------------------------------------------------------------------------------------------

bool SaveFiles(HWND owner, OPENFILENAME *ofn, LPSTR Title, LPSTR Title2000, LPCTSTR Filter, LPCTSTR defaultdir, char *PathName, int PathNameSize, char *FileName, int FileNameSize, int Flags, char *defaultext, int defindex)
{
retry:
	ZeroMemory(ofn, sizeof(OPENFILENAME));					//set buffer to zero
	CString l_InitialDir= ".\\";							//get a string for the path
	CWinApp *pApp = AfxGetApp();
	l_InitialDir = GetString(defaultdir, 0);
	SetCurrentDirectory(l_InitialDir);
	if (GetOSVersion() >= WINDOWS2000)						//WINDOWS2000 is defined in Globals.h along with this function
	{
		if (Title2000 == NULL)
			ofn->lpstrTitle = Title;
		else
			ofn->lpstrTitle = Title2000;
		ofn->lStructSize = sizeof(OPENFILENAME);
	}
	else
	{
		ofn->lpstrTitle = Title;
		ofn->lStructSize = OPENFILENAME_SIZE_VERSION_400;
	}
	ofn->hwndOwner=owner;
	ofn->lpstrFilter = Filter;	
	ofn->lpstrCustomFilter = NULL;
	ofn->nFilterIndex = defindex;
	ofn->lpstrFile = PathName;
	ofn->nMaxFile = PathNameSize;
	ofn->lpstrFileTitle = FileName;
	ofn->nMaxFileTitle = FileNameSize;
	ofn->lpstrInitialDir = l_InitialDir;
	ofn->Flags = Flags;
	ofn->lpstrDefExt = defaultext;
	ZeroMemory(PathName, PathNameSize); 
	ZeroMemory(FileName, FileNameSize);  
	GetSaveFileName(ofn);

	char WindowsDir[MAX_PATH];
	GetWindowsDirectory(WindowsDir, MAX_PATH);
	if (strstr(PathName, WindowsDir) != NULL)
	{
		AfxMessageBox("Illegal Folder,  please choose another folder. Read or Write to Windows is not permitted.");
			goto retry;
	}
//
//	AfxMessageBox(l_InitialDir);
//	AfxMessageBox(PathName);
	GetCurrentDirectory(MAX_PATH, l_InitialDir.GetBuffer(MAX_PATH));  //get curr dir
	l_InitialDir.ReleaseBuffer();
	if (PathName[0] == '\0')						//did user choose a file?
		return false;										//nope!
//	WriteString(defaultdir, (LPCTSTR)l_InitialDir);
	WriteString(defaultdir, (LPCTSTR)PathName);
	
	return true;
}
//----------------------------------------------------------------------------------------------
// int GetOSVersion()
// Detect Operating system and return it via an enum integer.
// PARAMETERS:	OSVERSIONINFOEX *osvi - pointer to a OSVERSIONINFOEX struct
//
// RETURN		int	- -1 = error, 0 = Win95, 1 = 98/ME, 2 = NTV4.0, 3 = Windows2000, 4 = XP, 5 = later NT
// enum {WINDOWS95 = 0, WINDOWS98ME, WINDOWSNT4, WINDOWS2000, WINDOWSXP, WINDOWSLATER, WINDOWSVISTA};
//----------------------------------------------------------------------------------------------
int GetOSVersion()
{
   	OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
    if (GetVersionEx ( (OSVERSIONINFO *) &osvi)) 
	{
		switch (osvi.dwPlatformId)
		{
			case VER_PLATFORM_WIN32_WINDOWS:
				if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
					return WINDOWS95;  //Windows 95
				else 
					return WINDOWS98ME;  //Windows 98/ME
			break;
			case VER_PLATFORM_WIN32_NT:
				switch (osvi.dwMajorVersion)
				{
					case 4:
						return WINDOWSNT4; //Windows NTV4.0
					break;
					case 5:
					{
						switch (osvi.dwMinorVersion)
						{
							case 0:
								return WINDOWS2000; //Windows 2000
							break;
							case 1:
								return WINDOWSXP; //Windows XP
							break;
							case 2:
								return WINDOWSSERVER2003; //Windows Server 2003 /  2003 R2
							break;
							default:
								return WINDOWSLATER; //Windows ??
							break;
						}
					}
					break;
					case 6:
						switch (osvi.dwMinorVersion)
						{
							case 0:
								return WINDOWSVISTA;  //Vista or Windows server 2008 (share the same kernel)
							break;
							case 1:
								return WINDOWS7;
							default:
								return WINDOWSVISTALATER; //Windows 7?
							break;
						}
					break;
					default:
						return WINDOWSBEYONDVISTA; //Windows ??
					break;
				}
			break;
			default:
				return WIN32_NTLATER; //Windows ??
			break;
		}
	}
	return -1;
}
void WriteRegistryString(HKEY key, LPCTSTR str, char *value, char *data)
{

  HKEY hk;
  RegCreateKey(key, str, &hk);
  RegSetValueEx(hk,                    // subkey handle 
			    value,   		       // value name 
				0,                     // must be zero 
				REG_SZ,             // value type 
				(LPBYTE)data,  // pointer to value data 
				(DWORD)strlen(data));
	RegCloseKey(hk);
}

void GetRegistryString(HKEY key, LPCTSTR str, char *value, LPBYTE szBuffer,  DWORD dwBuflen)
{
	HKEY hKey;
    RegOpenKeyEx(key, str,
                 0, KEY_QUERY_VALUE, &hKey );
    RegQueryValueEx(hKey, value, NULL, NULL,
               (LPBYTE) szBuffer, &dwBuflen);
    RegCloseKey( hKey );
}

void WriteInt(LPCTSTR str, int value)
{
	AfxGetApp()->WriteProfileInt(REGISTRYNAME, str, value);
}

void WriteString(LPCTSTR str, LPCTSTR value)
{
	AfxGetApp()->WriteProfileString(REGISTRYNAME, str, value);
}

UINT GetInt(LPCTSTR str, int value)
{
	return AfxGetApp()->GetProfileInt(REGISTRYNAME, str, value);
}

CString GetString(LPCTSTR str, LPCTSTR value)
{
	return AfxGetApp()->GetProfileString(REGISTRYNAME, str, value);
}

void memory_status()
{
#define WIDTH 7
#define DIV 1024
	char *divisor = "K";
	MEMORYSTATUSEX stat;
	stat.dwLength = sizeof (stat);
	
	GlobalMemoryStatusEx (&stat);
	SAFE_LOG(out, "Memory statistics", true);
	sprintf_s(str, 256, "%ld percent of memory is in use.", stat.dwMemoryLoad);
	SAFE_LOG(out, str, true);
	sprintf_s(str, 256,  "There are %*ld total %sB of physical memory.", WIDTH, stat.ullTotalPhys/DIV, divisor);
	SAFE_LOG(out, str, true);
	sprintf_s(str, 256, "There are %*ld free %sB of available physical memory.",  WIDTH, stat.ullAvailPhys/DIV, divisor);
	SAFE_LOG(out, str, true);
	sprintf_s(str, 256, "There are %*ld total %sB of paging file.",     WIDTH, stat.ullTotalPageFile/DIV, divisor);
	SAFE_LOG(out,  str, true);
	sprintf_s(str, 256, "There are %*ld free %sB of available paging file.",      WIDTH, stat.ullAvailPageFile/DIV, divisor);
	SAFE_LOG(out, str, true);
	sprintf_s(str, 256, "There are %*ld total %sB of virtual memory.",  WIDTH, stat.ullTotalVirtual/DIV, divisor);
	SAFE_LOG(out, str, true);
	sprintf_s(str, 256, "There are %*ld free %sB of available virtual memory.",   WIDTH, stat.ullAvailVirtual/DIV, divisor);
	SAFE_LOG(out, str, true);
}

double RandomNumber( double minnumber, double maxnumber )
{
    double range = maxnumber - minnumber;
    double num = range * (double)rand()/(double)RAND_MAX;
    return( num + minnumber );
}

//--------------------------------------------------------------------------------------------------
// int FileExists(char *file, bool create)
//
// Checks and reports if a passed filename exists, and optionally creates it if not..  
// PARAMETERS:	char *file	-  signed integer value of smallest number to return
//				bool create - OPTIONAL parameter,defaults to false,  if true file is created if it
//							  does not exist.
// RETURN:		int		    -  0 = file exists. -1 = it does not exist, 1= it was created		
//--------------------------------------------------------------------------------------------------
int FileExists(char *file, bool create)
{
	CFile f;
	if(f.Open(file, CFile::modeRead | CFile::typeBinary) != 0)
	{
		f.Close();
		return 0;
	}
	else if (create)
	{
		 if (f.Open(file, CFile::modeCreate) == 0)
		 	return -1;
		 else
		 {
			f.Close();
			return 1;
		 }
	}
	else
		return -1;
}


/*-------------------------------------------------------------------------

-
IsCurrentUserLocalAdministrator ()

This function checks the token of the calling thread to see if the caller
belongs to the Administrators group.

Return Value:
   TRUE if the caller is an administrator on the local machine. Or Windows98
   as administrator on those old os's is irrelevant.
   Otherwise, FALSE.
--------------------------------------------------------------------------*/

BOOL IsCurrentUserLocalAdministrator()
{

//	if (GetOSVersion() <= WINDOWS98ME)
//		return TRUE;
   BOOL   fReturn         = FALSE;
   DWORD  dwStatus;
   DWORD  dwAccessMask;
   DWORD  dwAccessDesired;
   DWORD  dwACLSize;
   DWORD  dwStructureSize = sizeof(PRIVILEGE_SET);
   PACL   pACL            = NULL;
   PSID   psidAdmin       = NULL;

   HANDLE hToken              = NULL;
   HANDLE hImpersonationToken = NULL;

   PRIVILEGE_SET   ps;
   GENERIC_MAPPING GenericMapping;

   PSECURITY_DESCRIPTOR     psdAdmin           = NULL;
   SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;


   /*Determine if the current thread is running as a user that is a member
	 of the local admins group.  To do this, create a security descriptor
	 that has a DACL which has an ACE that allows only local aministrators
	 access. Then, call AccessCheck with the current thread's token and the
	 security descriptor. It will say whether the user could access an object if
	 it had that security descriptor.  Note: you do not need to actually
	 create the object.  Just checking access against the security descriptor
	 alone will be sufficient.*/
   const DWORD ACCESS_READ  = 1;
   const DWORD ACCESS_WRITE = 2;
   __try
   {

      /*
         AccessCheck() requires an impersonation token.  We first get a
		 primary token and then create a duplicate impersonation token.  The
         impersonation token is not actually assigned to the thread, but is
         used in the call to AccessCheck.  Thus, this function itself never
         impersonates, but does use the identity of the thread.  If the
		 thread was impersonating already, this function uses that impersonation
		 context.
      */
      if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY, TRUE, &hToken))
      {
         if (GetLastError() != ERROR_NO_TOKEN)
            __leave;

         if (!OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
            __leave;
      }

      if (!DuplicateToken (hToken, SecurityImpersonation,&hImpersonationToken))
          __leave;
      /*
        Create the binary representation of the well-known SID that
        represents the local administrators group.  Then create the
		security descriptor and DACL with an ACE that allows only local admins
		access.  After that, perform the access check.  This will determine whether
        the current user is a local admin.
      */
      if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
                                    SECURITY_BUILTIN_DOMAIN_RID,
                                    DOMAIN_ALIAS_RID_ADMINS,
                                    0, 0, 0, 0, 0, 0, &psidAdmin))
         __leave;

      psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
      if (psdAdmin == NULL)
         __leave;

      if (!InitializeSecurityDescriptor(psdAdmin, SECURITY_DESCRIPTOR_REVISION))
         __leave;

      // Compute size needed for the ACL.
      dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD);

      pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
      if (pACL == NULL)
         __leave;

      if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
         __leave;

      dwAccessMask= ACCESS_READ | ACCESS_WRITE;

      if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin))
         __leave;

      if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
         __leave;

      /* AccessCheck validates a security descriptor somewhat; set the
		 group and owner so that enough of the security descriptor is filled out
		 to make AccessCheck happy.*/
      SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
      SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);

      if (!IsValidSecurityDescriptor(psdAdmin))
         __leave;

      dwAccessDesired = ACCESS_READ;

      /*
         Initialize GenericMapping structure even though you
         do not use generic rights.
      */
      GenericMapping.GenericRead    = ACCESS_READ;
      GenericMapping.GenericWrite   = ACCESS_WRITE;
      GenericMapping.GenericExecute = 0;
      GenericMapping.GenericAll     = ACCESS_READ | ACCESS_WRITE;

      if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
                       &GenericMapping, &ps, &dwStructureSize, &dwStatus,
                       &fReturn))
      {
         fReturn = FALSE;
         __leave;
      }
   }
   __finally
   {
      // Clean up.
      if (pACL) LocalFree(pACL);
      if (psdAdmin) LocalFree(psdAdmin);
      if (psidAdmin) FreeSid(psidAdmin);
      if (hImpersonationToken) CloseHandle (hImpersonationToken);
      if (hToken) CloseHandle (hToken);
   }

   return fReturn;
}

void DoGetLastError(CString *lpMsgBuf)
{
		LPVOID lpMsgBuf1;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
		FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, 
		SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf1, 0, NULL);
		*lpMsgBuf = (LPCTSTR)lpMsgBuf1;
		LocalFree( lpMsgBuf1 );		// Free the buffer.		
}


void GetProgramRunPath(char* sProgramPath)
{
	char  drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
	//_splitpath((char *)AfxGetApp()->m_pszHelpFilePath, drive, dir, fname, ext);
	_splitpath_s((char *)AfxGetApp()->m_pszHelpFilePath, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT );
	_makepath_s(sProgramPath, MAX_PATH,  drive, dir, NULL, NULL);

}

void GetVersion(CString *cFilePath, int stringsize)
{
	*cFilePath = (char *)AfxGetApp()->m_pszHelpFilePath;
	DWORD dwDummy;
	cFilePath->Replace(".HLP", ".exe");
	DWORD dwFVISize = GetFileVersionInfoSize( cFilePath->GetBuffer(0) , &dwDummy );
	LPBYTE lpVersionInfo = new BYTE[dwFVISize];
	GetFileVersionInfo( cFilePath->GetBuffer(0) , 0 , dwFVISize , lpVersionInfo );
	UINT uLen;
	VS_FIXEDFILEINFO *lpFfi;
	VerQueryValue( lpVersionInfo , _T("\\") , (LPVOID *)&lpFfi , &uLen );
	DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
	DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
	delete [] lpVersionInfo;
	//printf( "Higher: %x\n" , dwFileVersionMS );
	//printf( "Lower: %x\n" , dwFileVersionLS );
	DWORD dwLeftMost = HIWORD(dwFileVersionMS);
	DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
	DWORD dwSecondRight = HIWORD(dwFileVersionLS);
	DWORD dwRightMost = LOWORD(dwFileVersionLS);
	cFilePath->Format("%d%d%d%d" , dwLeftMost, dwSecondLeft,dwSecondRight, dwRightMost ); 
}

void GetFileVersionString(CString *cFilePath)
{
	*cFilePath = (char *)AfxGetApp()->m_pszHelpFilePath;
	DWORD dwDummy;
	cFilePath->Replace(".HLP", ".exe");
	DWORD dwFVISize = GetFileVersionInfoSize( cFilePath->GetBuffer(0) , &dwDummy );
	LPBYTE lpVersionInfo = new BYTE[dwFVISize];
	GetFileVersionInfo( cFilePath->GetBuffer(0) , 0 , dwFVISize , lpVersionInfo );
	UINT uLen;
	VS_FIXEDFILEINFO *lpFfi;
	VerQueryValue( lpVersionInfo , _T("\\") , (LPVOID *)&lpFfi , &uLen );
	DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
	DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
	delete [] lpVersionInfo;
	//printf( "Higher: %x\n" , dwFileVersionMS );
	//printf( "Lower: %x\n" , dwFileVersionLS );
	DWORD dwLeftMost = HIWORD(dwFileVersionMS);
	DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
	DWORD dwSecondRight = HIWORD(dwFileVersionLS);
	DWORD dwRightMost = LOWORD(dwFileVersionLS);
	cFilePath->Format("%d%d%d%d" , dwLeftMost, dwSecondLeft,dwSecondRight, dwRightMost ); 
}